package com.topscomm.mis.cbb.pm.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.topscomm.basic.BasicEntity;
import com.topscomm.basic.exception.BusinessException;
import com.topscomm.basic.exception.MessageException;
import com.topscomm.basic.exception.ServiceException;
import com.topscomm.basic.util.PrimaryKeyUtil;
import com.topscomm.cbo.pojo.*;
import com.topscomm.cbo.service.*;
import com.topscomm.mis.cbb.pm.api.IWbsService;
import com.topscomm.mis.cbb.pm.base.dto.AppMessageDTO;
import com.topscomm.mis.cbb.pm.base.pojo.CbbPmTaskBackRecordEntity;
import com.topscomm.mis.cbb.pm.base.pojo.CbbPmTaskConstraintEntity;
import com.topscomm.mis.cbb.pm.base.pojo.CbbPmTaskEntity;
import com.topscomm.mis.cbb.pm.base.pojo.CbbPmWbsEntity;
import com.topscomm.mis.cbb.pm.base.service.ICbbPmTaskBackRecordService;
import com.topscomm.mis.cbb.pm.base.service.ICbbPmTaskConstraintService;
import com.topscomm.mis.cbb.pm.base.service.ICbbPmTaskService;
import com.topscomm.mis.cbb.pm.base.service.ICbbPmWbsService;
import com.topscomm.mis.cbb.pm.enumerate.TaskStatusEnum;
import com.topscomm.mis.cbb.pm.service.abs.AbstractTaskService;
import com.topscomm.mis.cbb.pm.service.chain.handler.CompetitionHandler;
import com.topscomm.mis.cbb.pm.service.chain.handler.CountersignHandler;
import com.topscomm.mis.cbb.pm.service.chain.handler.OtherHandler;
import com.topscomm.mis.cbb.pm.service.chain.TaskCompleteHandler;
import com.topscomm.mis.service.msgbus.IMsgBusProducerService;
import com.topscomm.pub.util.*;
import com.topscomm.tap.TapService;
import com.topscomm.tap.common.SessionUserBean;
import com.topscomm.tap.common.TapSystemConst;
import com.topscomm.tap.util.ScriptUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.provider.approval.Approval;
import org.springframework.stereotype.Service;
import com.topscomm.mis.cbb.pm.util.FlowNode;
import com.topscomm.mis.cbb.pm.util.PmSystemConst;
import org.springframework.transaction.annotation.Transactional;
import com.topscomm.mis.cbb.pm.util.ServiceNameUtil;

import java.util.*;
import java.util.stream.Collectors;

import static com.topscomm.mis.cbb.pm.util.PmSystemConst.DEFAULTPARENTCODE;

@Service
public class TaskService extends AbstractTaskService {
    @Autowired
    private ICbbPmTaskService cbbPmTaskService;
    @Autowired
    private ICbbPmWbsService cbbPmWbsService;
    @Autowired
    private ICbbPmTaskConstraintService cbbPmTaskConstraintService;
    @Autowired
    private ICboUserService cboUserService;
    @Autowired
    private ICboApprovalNodeInsService cboApprovalNodeInsService;
    @Autowired
    private ICboApprovalNodeService cboApprovalNodeService;
    @Autowired
    private ICbbPmTaskBackRecordService cbbPmTaskBackRecordService;
    @Autowired
    private ICboApprovalFlowInsService cboApprovalFlowInsService;
    @Autowired
    private ICboDeptService cboDeptService;
    @Autowired
    private ICboOrgService cboOrgService;
    @Autowired
    private ICboRoleService cboRoleService;
    @Autowired
    private IMsgBusProducerService msgBusProducerService;
    @Autowired
    private IWbsService wbsService;

    private final List<Integer> notCompleteStatus = Arrays.asList(PmSystemConst.TaskStatus.NOTSTART, PmSystemConst.TaskStatus.READYSTART, PmSystemConst.TaskStatus.RUNNING, PmSystemConst.TaskStatus.CONFUSION);

    @Override
    public List<Integer> getNotCompleteStatus() {
        return this.notCompleteStatus;
    }

    /**
     * @param paramMap
     * @return java.util.Map<java.lang.String, java.lang.Object>
     * @description: 获取甘特图数据
     * @author: wangxinhua
     * @date: 2023/6/14 8:54
     * @modify:
     */
    @Override
    public Map<String, Object> getGanttInfo(Map<String, Object> paramMap) {
        if (!paramMap.containsKey("projectId") || StringUtil.isEmpty(ConvertUtil.convertToString(paramMap.get("projectId")))) {
            return null;
        }
        CbbPmWbsEntity wbsEntity = cbbPmWbsService.queryObjectByWhere(" projectuucode='"+paramMap.get("projectId")+"'");
        //获取WBS所有任务
        List<Map<String, Object>> taskList = cbbPmTaskService.queryMapByWhere(CbbPmTaskEntity.FieldWbscode + "='" +
                wbsEntity.getWbscode() + "' and planbegintime is not null  and planendtime is not null", "queryGanttTask");
        //获取任务约束
        StringBufferProxy whereSql = new StringBufferProxy();
        whereSql.appendSingle(" CBB_PM_TASK.WBSCODE='{0}' ", wbsEntity.getWbscode());
        List<Map<String, Object>> constraintList = cbbPmTaskService.queryMapByWhere(whereSql.toString(), "queryTaskWithConstraint");
        Map<String, Object> resMap = new HashMap<>();
        resMap.put("taskList", taskList);
        resMap.put("lineList", constraintList);
        return resMap;
    }

    @Override
    protected void beforeInsert(Map<String, Object> paramMap) {
        String originTaskCode = ConvertUtil.convertToString(paramMap.get(CbbPmTaskEntity.FieldOrigintaskcode));
        if (!StringUtil.isEmpty(originTaskCode)) {
            //若原始任务节点进行中，则任务状态赋值待进行
            CbbPmTaskEntity pmTaskEntity = cbbPmTaskService.queryObjectByWhere(" code='"+ originTaskCode +"'"+" and currently="+ PmSystemConst.CboYesNo.YES);
            if (StringUtil.isEmpty(pmTaskEntity.getNodeinsid())) {
                paramMap.put(CbbPmTaskEntity.FieldStatus, PmSystemConst.TaskStatus.NOTSTART);
            } else {
                paramMap.put(CbbPmTaskEntity.FieldStatus, PmSystemConst.TaskStatus.READYSTART);
            }
        }
    }

    /**
     * @description: 任务下发
     * @param paramMap
     * @return void
     * @author: wangxinhua
     * @date: 2023/6/15 13:54
     * @modify:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void issueTask(Map<String, Object> paramMap) {
        String taskIds = ConvertUtil.convertToString(paramMap.get("taskids"));
        if (StringUtil.isEmpty(taskIds)) {
            throw new MessageException("请选择要下发的任务");
        } else {
            Map<String, Object> updateMap = new HashMap<>();
            updateMap.put(CbbPmTaskEntity.FieldDeliverystatus, PmSystemConst.CboYesNo.YES);
            cbbPmTaskService.updateByWhere(updateMap, " id in ("+taskIds+")");
            List<CbbPmTaskEntity> cbbPmTaskEntityList = cbbPmTaskService.queryByWhere(" id in ("+taskIds+")");
            //发送消息
            List<AppMessageDTO> appMessageDTOList = new ArrayList<>();
            for (CbbPmTaskEntity taskEntity : cbbPmTaskEntityList) {
                AppMessageDTO appMessageDTO = new AppMessageDTO();
                appMessageDTO.setSourceid(taskIds);
                appMessageDTO.setMessagetype(PmSystemConst.sendMessageType.PUSH_NOTIFICATIONS);
                appMessageDTO.setSourcetype(CbbPmTaskEntity.tableName);
                appMessageDTO.setTitle("任务下发提醒");
                StringBufferProxy content = new StringBufferProxy();
                content.appendSingle("您所负责的任务[{0}]需要在{1}进行工作任务的开启", taskEntity.getName(), DateUtil.dateToString(taskEntity.getPlanbegintime(), "yyyy-MM-dd"));
                appMessageDTO.setContent(content.toString());
                appMessageDTO.setBanner(content.toString());
                appMessageDTO.setReceivecode(ConvertUtil.convertToString(taskEntity.getResponsibleusercode()));
            }
            msgBusProducerService.pushMsg("CboMessageSys", "INSERT", appMessageDTOList);
        }
    }

    /**
     * @description: 任务下发
     * @param paramMap
     * @return void
     * @author: wangxinhua
     * @date: 2023/6/15 13:54
     * @modify:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deliveryWbs(Map<String, Object> paramMap) {
        String projectUUCode = ConvertUtil.convertToString(paramMap.get("projectUUCode"));
        if (StringUtil.isEmpty(projectUUCode)) {
            throw new MessageException("请选择要下发的WBS");
        } else {
            CbbPmWbsEntity wbsEntity = cbbPmWbsService.queryObjectByWhere(" projectuucode='" + projectUUCode + "'");
            Map<String, Object> updateMap = new HashMap<>();
            updateMap.put(CbbPmTaskEntity.FieldDeliverystatus, PmSystemConst.CboYesNo.YES);
            StringBufferProxy whereSql = new StringBufferProxy();
            whereSql.appendSingle(" {0}='{1}' ", CbbPmTaskEntity.FieldWbscode, wbsEntity.getWbscode());
            whereSql.appendSingle(" and {0}={1} ", CbbPmTaskEntity.FieldDeliverystatus, PmSystemConst.CboYesNo.NO);
            cbbPmTaskService.updateByWhere(updateMap, whereSql.toString());
        }
    }

    /**
     * @author: hudeyong
     * @date: 2023-06-14
     * @description:初始化流程任务
     * @modify:
     */
    @Override
    public void initFlowTask(Map<String, Object> paraMap, List<FlowNode> flowNodeList, Map<String, Object> paramMap,String parentCode, String flowinsid, Boolean findRound, int loopTimes, int useTimes) {
        List<BasicEntity> taskList = new ArrayList<>();
        CbbPmWbsEntity pmWbsEntity = new CbbPmWbsEntity();
        pmWbsEntity.convertFromMap(paramMap);
        for (FlowNode nodeInfo : flowNodeList) {
            taskList.addAll(createTaskByNode(paraMap, nodeInfo,pmWbsEntity,parentCode,flowinsid, findRound, loopTimes, useTimes));
        }
        cbbPmTaskService.insertBatch(taskList);
    }

    /**
     * @author: hudeyong
     * @date: 2023-06-28
     * @description: 根据节点生成任务
     * @modify:
     */
    public List<BasicEntity> createTaskByNode(Map<String, Object> paraMap, FlowNode nodeInfo, CbbPmWbsEntity pmWbsEntity,String parentCode,String flowinsid, Boolean findRound, int looptimes, int useTimes) {
        List<BasicEntity> taskList = new ArrayList<>();
        // 通用数据赋值
        CbbPmTaskEntity generalTask = new CbbPmTaskEntity();
        // 固定赋值：项目编号、wbs编号、来源流程、特殊任务、第一轮、任务效力跟随节点效力
        generalTask.setProjectuucode(pmWbsEntity.getProjectuucode());
        generalTask.setWbscode(pmWbsEntity.getWbscode());
        generalTask.setSource(PmSystemConst.TaskSource.FLOW);
        generalTask.setType(PmSystemConst.TaskType.SPECIAL);
        if(findRound){
            // 计算轮次
            StringBufferProxy sql = new StringBufferProxy();
            sql.appendSingle("{0} = '{1}' and {2} = '{3}' and {4} = '{5}' and {6} = '{7}' and {8} = '{9}' ORDER BY ROUND DESC ",
                    CbbPmTaskEntity.FieldProjectuucode,pmWbsEntity.getProjectuucode(),
                    CbbPmTaskEntity.FieldNodeid,nodeInfo.getId(),
                    CbbPmTaskEntity.FieldLooptimes,looptimes,
                    CbbPmTaskEntity.FieldUsetimes,useTimes,
                    CbbPmTaskEntity.FieldSource,PmSystemConst.TaskSource.FLOW);
            List<CbbPmTaskEntity> tempList = cbbPmTaskService.queryByWhere(sql.toString());
            if(tempList.size()>0){
                generalTask.setRound(tempList.get(0).getRound() + 1);
            } else {
                generalTask.setRound(1);
            }
        } else {
            generalTask.setRound(1);
        }
        if(paraMap.containsKey("operateType") && ConvertUtil.convertToInt(paraMap.get("operateType")) == PmSystemConst.OperateWbsType.CREATE){
            generalTask.setDeliverystatus(PmSystemConst.CboYesNo.NO);
        } else {
            generalTask.setDeliverystatus(PmSystemConst.CboYesNo.YES);
        }
        if(nodeInfo.getApprovalParam()!=null && nodeInfo.getApprovalParam().containsKey("useTimes")){
            generalTask.setUsetimes(ConvertUtil.convertToInt(nodeInfo.getApprovalParam().get("useTimes")));
        } else {
            generalTask.setUsetimes(useTimes);
        }
        generalTask.setLooptimes(looptimes);
        generalTask.setFlowinsid(flowinsid);
        generalTask.setCurrently(1);
        generalTask.setFlowid(pmWbsEntity.getFlowid());
        generalTask.setEffectiveness(nodeInfo.getRuningState());
        // 肯定会有一个叫做node.name的任务，所以先赋值
        generalTask.setName(nodeInfo.getName());
        generalTask.setNodeid(nodeInfo.getId());
        generalTask.setSortCode(nodeInfo.getSortcode());
        // 默认任务效力为未开始
        int taskStatus = PmSystemConst.TaskStatus.NOTSTART;
        if (PmSystemConst.TaskRuningState.CONFUSION == nodeInfo.getRuningState()) {
            // 如果是待确定
            taskStatus = PmSystemConst.TaskStatus.CONFUSION;
        } else if (PmSystemConst.TaskRuningState.LOSE == nodeInfo.getRuningState()) {
            taskStatus = PmSystemConst.TaskStatus.LOSE;
        }
        // 审批人员
        List<Map<String, Object>> approvalUserList = nodeInfo.getPlanUser();
        String nodeType = nodeInfo.getNodetype();
        String parentCodeTemp = parentCode;
        CbbPmTaskEntity realityTask;
        if (PmSystemConst.NodeType.SINGLE.equals(nodeType)) {
            // 单人生成一个任务,添加人即可
        } else if (PmSystemConst.NodeType.SONFLOW.equals(nodeType)) {
            // 子流程节点，生成一个任务且自动通过
            generalTask.setAutocomplete(PmSystemConst.CboYesNo.YES);
        } else if (PmSystemConst.NodeType.COMPETITION.equals(nodeType)) {
            // 竞争，生成一个主任务，多个子任务，主任务autocomplete= true 自动完成，子任务relation = COMPETITION
            realityTask = (CbbPmTaskEntity) generalTask.clone();
            realityTask.setAutocomplete(PmSystemConst.CboYesNo.YES);
            long[] arrayId = PrimaryKeyUtil.GeneIDs(realityTask.getTableName(), 1);
            realityTask.setId(arrayId[0]);
            realityTask.setCode(PmSystemConst.CodePrefix.TASK + arrayId[0]);
            realityTask.setParentcode(parentCodeTemp);
            parentCodeTemp = PmSystemConst.CodePrefix.TASK + arrayId[0];
            taskList.add(realityTask);
            generalTask.setRelation(PmSystemConst.TaskRelation.COMPETITION);
        } else if (PmSystemConst.NodeType.COUNTERSIGN.equals(nodeType) || PmSystemConst.NodeType.COUNTERSIGNWAITING.equals(nodeType)) {
            // 会签、会签等待,，生成一个主任务，多个子任务，主任务autocomplete= true 自动完成，子任务relation = COUNTERSIGN
            realityTask = (CbbPmTaskEntity) generalTask.clone();
            realityTask.setAutocomplete(PmSystemConst.CboYesNo.YES);
            long[] arrayId = PrimaryKeyUtil.GeneIDs(realityTask.getTableName(), 1);
            realityTask.setId(arrayId[0]);
            realityTask.setCode(PmSystemConst.CodePrefix.TASK + arrayId[0]);
            realityTask.setParentcode(parentCodeTemp);
            parentCodeTemp = PmSystemConst.CodePrefix.TASK + arrayId[0];
            taskList.add(realityTask);
            generalTask.setRelation(PmSystemConst.TaskRelation.COUNTERSIGN);
        } else if (PmSystemConst.NodeType.CIRCULATION.equals(nodeType)) {
            // 自循环,生成多个主任务，根据审批人判断添加对应个数task即可
        }
        generalTask.setStatus(taskStatus);
        addTaskResponsible(taskList, generalTask, approvalUserList, parentCodeTemp);
        return taskList;
    }

    /**
     * @author: hudeyong
     * @date: 2023-06-14
     * @description: 添加任务责任人
     * @modify:
     */
    public void addTaskResponsible(List<BasicEntity> taskList, CbbPmTaskEntity generalTask, List<Map<String, Object>> approvalUserList, String parentCode){
        CbbPmTaskEntity realityTask;
        if(approvalUserList != null && approvalUserList.size()>0){
            for(Map<String, Object> userInfo : approvalUserList){
                realityTask = (CbbPmTaskEntity) generalTask.clone();
                long[] arrayId = PrimaryKeyUtil.GeneIDs(realityTask.getTableName(), 1);
                realityTask.setId(arrayId[0]);
                realityTask.setCode(PmSystemConst.CodePrefix.TASK+arrayId[0]);
                realityTask.setParentcode(parentCode);
                realityTask.setResponsibleusercode(ConvertUtil.convertToString(userInfo.get("code")));
                realityTask.setResponsibleusername(ConvertUtil.convertToString(userInfo.get("name")));
                taskList.add(realityTask);
            }
        } else {
            realityTask = (CbbPmTaskEntity) generalTask.clone();
            long[] arrayId = PrimaryKeyUtil.GeneIDs(realityTask.getTableName(), 1);
            realityTask.setId(arrayId[0]);
            realityTask.setCode(PmSystemConst.CodePrefix.TASK+arrayId[0]);
            realityTask.setParentcode(parentCode);
            taskList.add(realityTask);
        }

    }

    /**
     * @description: 开始任务
     * @param paramMap
     * @return void
     * @author: wangxinhua
     * @date: 2023/6/15 14:10
     * @modify:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void startTask(Map<String, Object> paramMap) {
        if (StringUtil.isEmpty(ConvertUtil.convertToString(paramMap.get("taskid")))) {
            throw new MessageException("请选择任务");
        }
        CbbPmTaskEntity taskEntity = cbbPmTaskService.queryById(ConvertUtil.convertToString(paramMap.get("taskid")));
        if (taskEntity.getStatus() != PmSystemConst.TaskStatus.NOTSTART && taskEntity.getStatus() != PmSystemConst.TaskStatus.READYSTART) {
            throw new MessageException("任务处于"+TaskStatusEnum.getNameByNumber(taskEntity.getStatus())+"状态当前任务状态无法开始");
        }
        //查询是否有约束条件
        StringBufferProxy whereSql = new StringBufferProxy();
        whereSql.appendSingle(" {0}='{1}' ", CbbPmTaskConstraintEntity.FieldTaskcode, taskEntity.getCode());
        whereSql.appendSingle(" and {0} in ({1}) ", CbbPmTaskConstraintEntity.FieldType, PmSystemConst.TaskConstraintType.STARTSTART + "," + PmSystemConst.TaskConstraintType.FINISHSTART);
        List<CbbPmTaskConstraintEntity> constraintList = cbbPmTaskConstraintService.queryByWhere(" taskcode='" + taskEntity.getCode() + "' ");
        boolean canStart = false;
        //没有约束
        if (constraintList.size() <= 0) {
            canStart = true;
        } else {
            //有约束
            String codeStr = constraintList.stream().map(s -> "\'" + s.getConstrainttaskcode() + "\'").collect(Collectors.joining(","));
            whereSql.clear();
            whereSql.appendSingle(" {0} in ({1}) ", CbbPmTaskEntity.FieldCode, codeStr);
            whereSql.appendSingle(" and {0} in ({1}) ", CbbPmTaskEntity.FieldCurrently, PmSystemConst.CboYesNo.YES);
            //查询约束任务
            List<CbbPmTaskEntity> constraintTasks = cbbPmTaskService.queryByWhere(whereSql.toString());
            Map<String, Object> taskStatusMap = new HashMap<>();
            for (CbbPmTaskEntity task : constraintTasks) {
                taskStatusMap.put(task.getCode(),task.getStatus());
            }
            for (CbbPmTaskConstraintEntity cbbPmTaskConstraintEntity : constraintList) {
                int status = ConvertUtil.convertToInt(taskStatusMap.get(cbbPmTaskConstraintEntity.getConstrainttaskcode()));
                if (PmSystemConst.TaskConstraintType.STARTSTART == cbbPmTaskConstraintEntity.getType()) {
                    // 其他任务开始本任务才能开始
                    if (status == PmSystemConst.TaskStatus.NOTSTART || status == PmSystemConst.TaskStatus.READYSTART) {
                        throw new MessageException("任务编号为："+cbbPmTaskConstraintEntity.getConstrainttaskcode()+"的任务未开始，无法开始当前任务");
                    }
                }
                if (PmSystemConst.TaskConstraintType.FINISHSTART == cbbPmTaskConstraintEntity.getType()) {
                    //其他任务完成本任务才能开始
                    if (status != PmSystemConst.TaskStatus.COMPLETE) {
                        throw new MessageException("任务编号为："+cbbPmTaskConstraintEntity.getConstrainttaskcode()+"的任务未完成，无法开始当前任务");
                    }
                }
            }
        }
        //可以开始更新状态
        if (canStart) {
            Map<String, Object> updateMap = new HashMap<>();
            updateMap.put(CbbPmTaskEntity.FieldStatus, PmSystemConst.TaskStatus.RUNNING);
            updateMap.put(CbbPmTaskEntity.FieldRealbegintime, new Date());
            cbbPmTaskService.updateByWhere(updateMap, " id="+taskEntity.getId());
            //获取所有未开始，带进行的父级开始任务
            Map<String, Object> parentParam = new HashMap<>();
            parentParam.put("taskcode",taskEntity.getCode());
            parentParam.put("whereSql", " status in (0,1) ");
            List<Map<String, Object>> parentList = cbbPmTaskService.queryMap(parentParam, "queryTaskParentTask");
            if (parentList.size() > 0) {
                String idStr = parentList.stream().map(s -> ConvertUtil.convertToString(s.get("id"))).collect(Collectors.joining(","));
                cbbPmTaskService.updateByWhere(updateMap, " id in （"+idStr+")");
            }
        }
    }

    /**
     * @description: 完成任务
     * @param paramMap
     * @return void
     * @author: wangxinhua
     * @date: 2023/6/15 14:10
     * @modify:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void completeTask(Map<String, Object> paramMap) {
        if (StringUtil.isEmpty(ConvertUtil.convertToString(paramMap.get("taskid")))) {
            throw new MessageException("请选择任务");
        }
        Map<String, Object> taskInfo = cbbPmTaskService.queryMapById(ConvertUtil.convertToString(paramMap.get("taskid")));
        //校验任务是否可以关闭
        Map<String, Object> validateRes = validateComplete(taskInfo, false);
        if (!ConvertUtil.convertToBoolean(validateRes.get("canComplete"))) {
            throw new MessageException(ConvertUtil.convertToString(validateRes.get("message")));
        }
        this.taskChainHandler(taskInfo);
        //查询节点实例下所有任务是否已完成，若都已完成则调用审批节点审批通过方法
        this.taskExecuteNextNode(taskInfo);
    }

    private void taskExecuteNextNode(Map<String, Object> taskInfo) {
        //查询节点实例下所有任务是否已完成，若都已完成则调用审批节点审批通过方法
        StringBufferProxy nodeNotCompleteSql = new StringBufferProxy();
        nodeNotCompleteSql.appendSingle(" {0}='{1}' ", CbbPmTaskEntity.FieldWbscode, taskInfo.get(CbbPmTaskEntity.FieldWbscode));
        nodeNotCompleteSql.appendSingle(" and {0}='{1}' ", CbbPmTaskEntity.FieldNodeid, taskInfo.get(CbbPmTaskEntity.FieldNodeid));
        nodeNotCompleteSql.appendSingle(" and {0}='{1}' ", CbbPmTaskEntity.FieldNodeinsid, taskInfo.get(CbbPmTaskEntity.FieldNodeinsid));
        nodeNotCompleteSql.appendSingle(" and {0}='{1}' ", CbbPmTaskEntity.FieldCurrently, PmSystemConst.CboYesNo.YES);
        nodeNotCompleteSql.appendSingle(" and {0} in ({1}) ", CbbPmTaskEntity.FieldStatus, StringUtils.join(notCompleteStatus, ","));
        int nodeNotCompleteNum = cbbPmTaskService.getCount(nodeNotCompleteSql.toString());
        //如果有未完成的任务不执行后续审批操作,获取nodeidsid为空
        if (nodeNotCompleteNum > 0 || StringUtil.isEmpty(ConvertUtil.convertToString(taskInfo.get(CbbPmTaskEntity.FieldNodeinsid)))) {
            return;
        }
        CboApprovalNodeInsEntity nodeInsEntity = cboApprovalNodeInsService.queryById(ConvertUtil.convertToString(taskInfo.get(CbbPmTaskEntity.FieldNodeinsid)));
        SessionUserBean approvalSessionUserBean = this.generateSessionUserBean("", nodeInsEntity.getApprovaluserid());
        // 节点审批通过
        String serviceName = ServiceNameUtil.getNameBySourceType(nodeInsEntity.getSourcetype());
        TapService tapService = (TapService) SpringUtil.getBean(serviceName);
        tapService.executeApprove(ConvertUtil.convertToString(taskInfo.get(CbbPmTaskEntity.FieldNodeinsid)), new Date(), "WBS任务完成", "1", "0",
                approvalSessionUserBean, 0L);
    }
    /**
     * @description: 在审批流程的afterapproval中调用,更新当前节点下一步节点关联任务的信息
     * @param nodeEntity
     * @return void
     * @author: wangxinhua
     * @date: 2023/6/19 15:36
     * @modify:
     */
    @Override
    public void refreshNextTaskInfo(Map<String, Object> docInfo, CboApprovalNodeEntity nodeEntity, CboApprovalNodeInsEntity nodeInsEntity) {
        // todo::调用生成wbs的对比方法

        //查询待审批节点实例
        StringBufferProxy whereSql = new StringBufferProxy();
        whereSql.appendSingle(" {0}='{1}' ", CboApprovalNodeInsEntity.FieldSourceid, nodeInsEntity.getSourceid());
        whereSql.appendSingle(" and {0}='{1}' ", CboApprovalNodeInsEntity.FieldSourcetype, nodeInsEntity.getSourcetype());
        whereSql.appendSingle(" and {0}='{1}' ", CboApprovalNodeInsEntity.FieldFlowinsid, nodeInsEntity.getFlowinsid());
        whereSql.appendSingle(" and {0}='{1}' ", CboApprovalNodeInsEntity.FieldState, TapSystemConst.TapApprovalNodeStateEnum.Approveing);
        List<Map<String, Object>> nextNodeInsEntities = cboApprovalNodeInsService.queryMapByWhere(whereSql.toString(), "com.topscomm.mis.cbb.pm.base.pojo.CbbPmTaskEntity.queryNodeInsWithNodeType");
        //获取节点信息
        List<String> nextNodeIds = new ArrayList<>();
        List<Map<String, Object>> nextNodeMap = nextNodeInsEntities.stream().map(m -> {
            nextNodeIds.add(ConvertUtil.convertToString(m.get("nodeid")));
            Map<String, Object> newMap = new HashMap<>();
            newMap.put("nodeid", m.get("nodeid"));
            newMap.put("nodetype", m.get("nodetype"));
            return newMap;}).distinct().collect(Collectors.toList());

        whereSql.clear();
        //查询当前项目任务是节点生成的
        whereSql.appendSingle(" {0}='{1}' ", CbbPmTaskEntity.FieldProjectuucode, docInfo.get("projectuucode"));
        whereSql.appendSingle(" and {0} in ({1}) ", CbbPmTaskEntity.FieldNodeid, StringUtils.join(nextNodeIds, ","));
        whereSql.appendSingle(" and {0}='{1}' ", CbbPmTaskEntity.FieldSource, PmSystemConst.TaskSource.FLOW);
        whereSql.appendSingle(" and {0}='{1}' ", CbbPmTaskEntity.FieldFlowinsid, nodeInsEntity.getFlowinsid());
        whereSql.appendSingle(" and {0}='{1}' ", CbbPmTaskEntity.FieldCurrently, PmSystemConst.CboYesNo.YES);
        whereSql.appendSingle(" and {0} is null ", CbbPmTaskEntity.FieldNodeinsid);
        List<CbbPmTaskEntity> taskEntities = cbbPmTaskService.queryByWhere(whereSql.toString());

        List<Integer> multitaskNodeType = Arrays.asList(TapSystemConst.TapApprovalNodeTypeEnum.CompetitionNode, TapSystemConst.TapApprovalNodeTypeEnum.SignNode, TapSystemConst.TapApprovalNodeTypeEnum.SignWaitNode);
        for (Map<String, Object> nodeMap : nextNodeMap) {
            int nodeType = ConvertUtil.convertToInt(nodeMap.get("nodetype"));
            List<Map<String, Object>> oneNodeIns = nextNodeInsEntities.stream().filter(item -> ConvertUtil.convertToString(item.get("nodeid")).equals(ConvertUtil.convertToString(nodeMap.get("nodeid")))).collect(Collectors.toList());
            // 处理各类型任务
            if (nodeType == TapSystemConst.TapApprovalNodeTypeEnum.SingleNode && oneNodeIns.size() > 0) {
                //如果是单人节点
                for (CbbPmTaskEntity taskEntity : taskEntities) {
                    if (ConvertUtil.convertToString(taskEntity.getNodeid()).equals(ConvertUtil.convertToString(nodeMap.get("nodeid")))) {
                        Map<String, Object> taskUpdateMap = new HashMap<>();
                        taskUpdateMap.put(CbbPmTaskEntity.FieldStatus, PmSystemConst.TaskStatus.READYSTART);
                        taskUpdateMap.put(CbbPmTaskEntity.FieldResponsibleusercode, ConvertUtil.convertToString(oneNodeIns.get(0).get("approvalusercode")));
                        taskUpdateMap.put(CbbPmTaskEntity.FieldResponsibleusername, ConvertUtil.convertToString(oneNodeIns.get(0).get("approvalusername")));
                        taskUpdateMap.put(CbbPmTaskEntity.FieldNodeinsid, ConvertUtil.convertToString(oneNodeIns.get(0).get("id")));
                        if (taskEntity.getPlanbegintime() == null) {
                            this.setPlanDate(taskUpdateMap, nodeEntity, ConvertUtil.convertToDate(oneNodeIns.get(0).get("startdate")));
                        }
                        //更新节点未启动的
                        whereSql.clear();
                        whereSql.appendSingle(" {0}='{1}' ", CbbPmTaskEntity.FieldProjectuucode, docInfo.get("projectuucode"));
                        whereSql.appendSingle(" and {0}='{1}' ", CbbPmTaskEntity.FieldNodeid, taskEntity.getNodeid());
                        whereSql.appendSingle(" and {0}='{1}' ", CbbPmTaskEntity.FieldFlowinsid, taskEntity.getFlowinsid());
                        whereSql.appendSingle(" and {0}={1} ", CbbPmTaskEntity.FieldCurrently, PmSystemConst.CboYesNo.YES);
                        whereSql.appendSingle(" and {0} in (0, 1, 5) ", CbbPmTaskEntity.FieldStatus);
                        cbbPmTaskService.updateByWhere(taskUpdateMap, whereSql.toString());
                        //更新已开始的
                        whereSql.clear();
                        taskUpdateMap.remove(CbbPmTaskEntity.FieldStatus);
                        whereSql.appendSingle(" {0}='{1}' ", CbbPmTaskEntity.FieldProjectuucode, docInfo.get("projectuucode"));
                        whereSql.appendSingle(" and {0}='{1}' ", CbbPmTaskEntity.FieldNodeid, taskEntity.getNodeid());
                        whereSql.appendSingle(" and {0}='{1}' ", CbbPmTaskEntity.FieldFlowinsid, taskEntity.getFlowinsid());
                        whereSql.appendSingle(" and {0}={1} ", CbbPmTaskEntity.FieldCurrently, PmSystemConst.CboYesNo.YES);
                        whereSql.appendSingle(" and {0} in (2) ", CbbPmTaskEntity.FieldStatus);
                        cbbPmTaskService.updateByWhere(taskUpdateMap, whereSql.toString());
                    }
                }
            } else if (nodeType == TapSystemConst.TapApprovalNodeTypeEnum.AutoLoopNode && oneNodeIns.size() > 0) {
                //自循环节点
                List<Map<String, Object>> updateMapList = new ArrayList<>();
                for (Map<String, Object> nextNodeInsEntity : oneNodeIns) {
                    for (CbbPmTaskEntity taskEntity : taskEntities) {
                        boolean haveUpdate = false;
                        if (ConvertUtil.convertToString(nextNodeInsEntity.get("nodeid")).equals(taskEntity.getNodeid()) && ConvertUtil.convertToString(nextNodeInsEntity.get("approvalusercode")).equals(taskEntity.getResponsibleusercode())) {
                            taskEntity.setStatus(PmSystemConst.TaskStatus.READYSTART);
                            taskEntity.setNodeinsid(ConvertUtil.convertToString(nextNodeInsEntity.get("id")));
                            if (taskEntity.getPlanbegintime() == null) {
                                this.setPlanDate(taskEntity, nodeEntity, ConvertUtil.convertToDate(oneNodeIns.get(0).get("startdate")));
                            }
                            //更新所有同级、子级人工任务
                            this.updateLabourTaskNodeIns(taskEntity, nodeEntity, oneNodeIns);
                            updateMapList.add(taskEntity.convertToMap());
                            haveUpdate = true;
                        }
                        if (haveUpdate) {
                            break;
                        }
                    }
                }
                cbbPmTaskService.updateBatchMap(updateMapList);
            } else if (multitaskNodeType.contains(nodeType)) {
                List<Map<String, Object>> updateMapList = new ArrayList<>();
                //竞争、会签、会签等待
                for (Map<String, Object> nextNodeInsEntity : oneNodeIns) {
                    for (CbbPmTaskEntity taskEntity : taskEntities) {
                        if (ConvertUtil.convertToString(nextNodeInsEntity.get("nodeid")).equals(taskEntity.getNodeid()) && ConvertUtil.convertToString(nextNodeInsEntity.get("approvalusercode")).equals(taskEntity.getResponsibleusercode())) {
                            taskEntity.setStatus(PmSystemConst.TaskStatus.READYSTART);
                            taskEntity.setNodeinsid(ConvertUtil.convertToString(nextNodeInsEntity.get("id")));
                            if (taskEntity.getPlanbegintime() == null) {
                                this.setPlanDate(taskEntity, nodeEntity, ConvertUtil.convertToDate(oneNodeIns.get(0).get("startdate")));
                            }
                            //更新所有同级、子级人工任务
                            this.updateLabourTaskNodeIns(taskEntity, nodeEntity, oneNodeIns);
                            updateMapList.add(taskEntity.convertToMap());
                        }
                    }
                }
                cbbPmTaskService.updateBatchMap(updateMapList);
            }
        }
    }

    /***
     * @description: 刷新子流程所有节点任务计划时间
     * @param parentEntity
     * @param subEntity
     * @return void
     * @author: wangxinhua
     * @date: 2023/7/13 20:13
     * @modify:
     */
    @Override
    public void refreshSonNodeDateTime(CboApprovalNodeInsEntity parentEntity, CboApprovalNodeInsEntity subEntity) {
        Map<String, Object> updateMap = new HashMap<>();
        updateMap.put("planbegintime", parentEntity.getStartdate());
        updateMap.put("planendtime", parentEntity.getPlanenddate());
        cbbPmTaskService.updateByWhere(updateMap, "FLOWINSID  = '" + subEntity.getFlowinsid() + "'");
    }

    private void updateLabourTaskNodeIns(CbbPmTaskEntity taskEntity, CboApprovalNodeEntity nodeEntity, List<Map<String, Object>> oneNodeIns) {
        StringBufferProxy whereSql = new StringBufferProxy();
        Map<String, Object> taskUpdateMap = new HashMap<>();
        taskUpdateMap.put(CbbPmTaskEntity.FieldStatus, PmSystemConst.TaskStatus.READYSTART);
        taskUpdateMap.put(CbbPmTaskEntity.FieldNodeinsid, ConvertUtil.convertToString(oneNodeIns.get(0).get("id")));
        taskUpdateMap.put(CbbPmTaskEntity.FieldPlanbegintime, taskEntity.getPlanbegintime());
        taskUpdateMap.put(CbbPmTaskEntity.FieldPlanendtime, taskEntity.getPlanendtime());
        if (taskEntity.getPlanbegintime() == null) {
            this.setPlanDate(taskUpdateMap, nodeEntity, ConvertUtil.convertToDate(oneNodeIns.get(0).get("startdate")));
        }
        //获取任务的同级人工任务以及所有人工子任务
        Map<String, Object> allSonTaskQuery = new HashMap<>();
        allSonTaskQuery.put("taskcode", taskEntity.getCode());
        allSonTaskQuery.put("projectuucode", taskEntity.getProjectuucode());
        List<Map<String, Object>> allSonTask = cbbPmTaskService.queryMap(allSonTaskQuery,"queryAllSubTaskByParentCode");
        if (allSonTask.size() <= 0) {
            return;
        }
        String nodeidsstr = allSonTask.stream().map(s -> s.get("id").toString()).collect(Collectors.joining(","));
        //更新节点未启动的
        whereSql.clear();
        whereSql.appendSingle(" id in ({0}) ", nodeidsstr);
        whereSql.appendSingle(" and {0}='{1}' ", CbbPmTaskEntity.FieldNodeid, taskEntity.getNodeid());
        whereSql.appendSingle(" and {0}='{1}' ", CbbPmTaskEntity.FieldFlowinsid, taskEntity.getFlowinsid());
        whereSql.appendSingle(" and {0} in (0,1,5) ", CbbPmTaskEntity.FieldStatus);
        cbbPmTaskService.updateByWhere(taskUpdateMap, whereSql.toString());
        //更新已开始的
        whereSql.clear();
        taskUpdateMap.remove(CbbPmTaskEntity.FieldStatus);
        whereSql.appendSingle(" id in ({0}) ", nodeidsstr);
        whereSql.appendSingle(" and {0}='{1}' ", CbbPmTaskEntity.FieldNodeid, taskEntity.getNodeid());
        whereSql.appendSingle(" and {0}='{1}' ", CbbPmTaskEntity.FieldFlowinsid, taskEntity.getFlowinsid());
        whereSql.appendSingle(" and {0} in (2) ", CbbPmTaskEntity.FieldStatus);
        cbbPmTaskService.updateByWhere(taskUpdateMap, whereSql.toString());
    }

    /**
     * @description: 设置计划开始时间
     * @param taskEntity
     * @param nodeEntity
     * @return void
     * @author: wangxinhua
     * @date: 2023/6/20 17:19
     * @modify:
     */
    private void setPlanDate(CbbPmTaskEntity taskEntity, CboApprovalNodeEntity nodeEntity, Date approvalStartDate) {
        // 获取当前时间
        Calendar now = Calendar.getInstance();
        now.setTime(approvalStartDate); //将日历设置为当前日期
        now.add(Calendar.DATE, nodeEntity.getPlanday()); //将日期增加一天
        Date newDate = now.getTime(); //获取新增后的日期
        taskEntity.setPlanbegintime(approvalStartDate);
        taskEntity.setPlanendtime(newDate);
    }
    /**
     * @description: 设置计划开始时间
     * @param taskUpdateMap
     * @param nodeEntity
     * @return void
     * @author: wangxinhua
     * @date: 2023/6/20 17:19
     * @modify:
     */
    private void setPlanDate(Map<String, Object> taskUpdateMap, CboApprovalNodeEntity nodeEntity, Date approvalStartDate) {
        // 获取当前时间
        Calendar now = Calendar.getInstance();
        now.setTime(approvalStartDate); //将日历设置为当前日期
        now.add(Calendar.DATE, nodeEntity.getPlanday()); //将日期增加一天
        Date newDate = now.getTime(); //获取新增后的日期
        taskUpdateMap.put(CbbPmTaskEntity.FieldPlanbegintime, approvalStartDate);
        taskUpdateMap.put(CbbPmTaskEntity.FieldPlanendtime, newDate);
    }
    /***
     * @description: 检验任务是否可以开始
     * @param taskInfo
     * @return java.util.Map<java.lang.String,java.lang.Object>
     * @author: wangxinhua
     * @date: 2023/6/16 16:41
     * @modify:
     */
    @Override
    public Map<String, Object> validateComplete(Map<String, Object> taskInfo, boolean autoValidate) {
        Map<String, Object> res = new HashMap<>();
        res.put("canComplete", true);
        //如果校验自动任务、手动任务
        if (autoValidate && ConvertUtil.convertToInt(taskInfo.get(CbbPmTaskEntity.FieldAutocomplete)) == PmSystemConst.TaskAutoComplete.LABOUR) {
            res.put("canComplete", false);
            res.put("message", "当前任务为手动任务，无法自动完成");
            return res;
        }
        //当前任务是否有子任务，子任务是否都完成了
        int subCount = this.notCompleteNum(taskInfo, PmSystemConst.TaskAddType.NEXT);
        if (subCount > 0) {
            res.put("canComplete", false);
            res.put("message", "当前存在未完成的子任务，请先完成子任务再完成当前任务");
            return res;
        }
        //当前是否是否有约束，约束是否可通过
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("taskcode", taskInfo.get(CbbPmTaskEntity.FieldCode));
        paramMap.put("wbscode", taskInfo.get(CbbPmTaskEntity.FieldWbscode));
        List<Map<String, Object>> constraintNumList = cbbPmTaskService.queryMap(paramMap, "queryTaskCompleteConstraintNum");
        if (constraintNumList.size() > 0) {
            for (Map<String, Object> constraint : constraintNumList) {
                int num  = ConvertUtil.convertToInt(constraint.get("constraint"));
                int type  = ConvertUtil.convertToInt(constraint.get("type"));
                String name  = ConvertUtil.convertToString(constraint.get("name"));
                if (num > 0) {
                    res.put("canComplete", false);
                    StringBuilder message = new StringBuilder("当前存在前置任务[").append(name).append("]");
                    if (type == PmSystemConst.TaskConstraintType.STARTFINISH) {
                        message.append("未开始");
                    } else if (type == PmSystemConst.TaskConstraintType.FINISHFINISH) {
                        message.append("未完成");
                    } else {
                        message.append("未执行");
                    }
                    message.append(",请先处理该前置任务！");
                    res.put("message", message.toString());
                    break;
                }
            }
        }
        return res;
    }

    @Override
    public int notCompleteNum(Map<String, Object> taskInfo, int type) {
        StringBufferProxy whereSql = new StringBufferProxy();
        whereSql.appendSingle(" {0}='{1}' ", CbbPmTaskEntity.FieldParentcode, taskInfo.get(type == PmSystemConst.TaskAddType.NEXT ?CbbPmTaskEntity.FieldCode : CbbPmTaskEntity.FieldParentcode));
        whereSql.appendSingle(" and {0}={1} ", CbbPmTaskEntity.FieldCurrently, PmSystemConst.CboYesNo.YES);
        whereSql.appendSingle(" and {0} in ({1}) ", CbbPmTaskEntity.FieldStatus, StringUtils.join(notCompleteStatus, ","));
        return cbbPmTaskService.getCount(whereSql.toString());
    }

    /**
     * @description: 责任链
     * @param taskInfo
     * @return void
     * @author: wangxinhua
     * @date: 2023/7/6 20:13
     * @modify:
     */
    protected void taskChainHandler(Map<String, Object> taskInfo) {
        // todo::放到configration,定义一次链条，提前定义
        //会签
        TaskCompleteHandler countersignHandler = new CountersignHandler();
        //竞争
        TaskCompleteHandler competitionHandler = new CompetitionHandler();
        //其他
        TaskCompleteHandler otherHandler = new OtherHandler();
        //创建职责链
        competitionHandler.setNextHandler(countersignHandler);
        countersignHandler.setNextHandler(otherHandler);
        competitionHandler.completeTask(taskInfo);
        if (!StringUtil.isEmpty(ConvertUtil.convertToString(taskInfo.get(CbbPmTaskEntity.FieldParentcode)))) {
            //查询父级任务
            CbbPmTaskEntity taskEntity = cbbPmTaskService.queryObjectByWhere("code='" + ConvertUtil.convertToString(taskInfo.get(CbbPmTaskEntity.FieldParentcode))+"'"+" and currently="+ PmSystemConst.CboYesNo.YES);
            if (taskEntity == null) {
                return;
            }
            //查询父级任务是否可以完成
             Map<String, Object> validateRes = this.validateComplete(taskEntity.convertToMap(), true);
            if (ConvertUtil.convertToBoolean(validateRes.get("canComplete"))) {
                this.taskChainHandler(taskEntity.convertToMap());
            }
        }
    }

    /**
     * @description: 退回任务
     * @param paramMap
     * @return void
     * @author: wangxinhua
     * @date: 2023/6/15 14:10
     * @modify:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void backTask(Map<String, Object> paramMap) {
        if (StringUtil.isEmpty(ConvertUtil.convertToString(paramMap.get("taskid")))) {
            throw new MessageException("请选择任务");
        }
        Map<String, Object> taskInfo = cbbPmTaskService.queryMapById(ConvertUtil.convertToString(paramMap.get("taskid")));
        CboApprovalNodeInsEntity nodeInsEntity = cboApprovalNodeInsService.queryById(ConvertUtil.convertToString(taskInfo.get(CbbPmTaskEntity.FieldNodeinsid)));
        CboApprovalNodeEntity nodeEntity = cboApprovalNodeService.queryById(ConvertUtil.convertToString(taskInfo.get(CbbPmTaskEntity.FieldNodeid)));
        //校验任务是否可以退回
        Map<String, Object> validateRes = validateBack(taskInfo, nodeEntity);
        if (!ConvertUtil.convertToBoolean(validateRes.get("canComplete"))) {
            throw new MessageException(ConvertUtil.convertToString(validateRes.get("message")));
        }
        SessionUserBean approvalSessionUserBean = this.generateSessionUserBean("", nodeInsEntity.getApprovaluserid());
        //取消子流程审批
        //退回节点id
        String backNodeId = nodeEntity.getBackexp().substring(7);
        this.deleteSonFlowInfo(taskInfo, nodeInsEntity, backNodeId);
        // 节点审批退回
        String serviceName = ServiceNameUtil.getNameBySourceType(nodeInsEntity.getSourcetype());
        TapService tapService = (TapService) SpringUtil.getBean(serviceName);
        tapService.executeApprove(ConvertUtil.convertToString(taskInfo.get(CbbPmTaskEntity.FieldNodeinsid)), new Date(), "WBS任务退回", "2", "0",
                approvalSessionUserBean, 0L);
    }

    /**
     * @description: 删除子流程的审批节点,审批节点实例
     * @param taskInfo
     * @param nodeInsEntity
     * @return void
     * @author: wangxinhua
     * @date: 2023/6/25 16:10
     * @modify:
     */
    private void deleteSonFlowInfo(Map<String, Object> taskInfo, CboApprovalNodeInsEntity nodeInsEntity, String backNodeId) {
        //获取节点中获取子流程节点是否在
        Map<String, Object> betweenNodeParam = new HashMap<>();
        betweenNodeParam.put("startNodeId", backNodeId);
        betweenNodeParam.put("endNodeId", nodeInsEntity.getNodeid());
        betweenNodeParam.put("flowInsId", nodeInsEntity.getFlowinsid());
        betweenNodeParam.put("flowId", nodeInsEntity.getFlowid());
        betweenNodeParam.put("sourceId", nodeInsEntity.getSourceid());
        betweenNodeParam.put("sourceType", nodeInsEntity.getSourcetype());
        betweenNodeParam.put("includeStart", true); //包含当前节点的任务生成
        List<FlowNode> betweenNode = wbsService.queryWbsNodeList(betweenNodeParam);
        String nodeidsstr = betweenNode.stream().map(s -> "'" + s.getId() + "'").collect(Collectors.joining(","));
        Map<String, Object> nodeParam = new HashMap<>();
        nodeParam.put("projectuucode", taskInfo.get(CbbPmTaskEntity.FieldProjectuucode));
        nodeParam.put("nodeids", nodeidsstr);
        nodeParam.put("flowinsid", nodeInsEntity.getFlowinsid());
        List<Map<String, Object>> flowIns = this.getAllSubTaskByNode(nodeParam, true);
        //取消所有任务关联的流程实例流程
//        StringBufferProxy nodeNotCompleteSql = new StringBufferProxy();
//        nodeNotCompleteSql.appendSingle(" {0}='{1}' and NODEINSID is not null ", CbbPmTaskEntity.FieldProjectuucode, taskInfo.get(CbbPmTaskEntity.FieldProjectuucode));
//        List<Map<String, Object>> flowIns = cbbPmTaskService.queryMapByWhere(nodeNotCompleteSql.toString(),"queryTaskFlowIns");
        List<String> flowInsIds= new ArrayList<>();
        // 等于当前审批流程实例的流程
        for (Map<String, Object> flowIn : flowIns) {
            if (ConvertUtil.convertToLong(flowIn.get("id")) != nodeInsEntity.getFlowinsid()) {
                //如果子流程还在审批中则记录，后续更新审批流程、节点状态
                if (ConvertUtil.convertToInt(flowIn.get("state")) == TapSystemConst.TapApprovalFlowStateEnum.Approveing) {
                    flowInsIds.add(ConvertUtil.convertToString(flowIn.get("id")));
                }
                //更新单据状态
                String serviceName = ServiceNameUtil.getNameBySourceType(ConvertUtil.convertToString(flowIn.get("sourcetype")));
                TapService tapService = (TapService) SpringUtil.getBean(serviceName);
                Map<String, Object> sonUpdateMap = new HashMap<>();
                sonUpdateMap.put("id", flowIn.get("sourceid"));
                sonUpdateMap.put("state", TapSystemConst.TapApprovalFlowStateEnum.Back);
                tapService.update(sonUpdateMap);
            }
        }
        //更新子流程状态
        if (flowInsIds.size() > 0) {
            Map<String, Object> backUpdateMap = new HashMap<>();
            backUpdateMap.put("state", TapSystemConst.TapApprovalFlowStateEnum.Back);
            StringBufferProxy sql = new StringBufferProxy();
            sql.appendSingle(" id in ({0}) ", StringUtils.join(flowInsIds, ","));
            cboApprovalFlowInsService.updateByWhere(backUpdateMap, sql.toString());
            sql.clear();
            backUpdateMap.clear();
            backUpdateMap.put("state", TapSystemConst.TapApprovalNodeStateEnum.Close);
            sql.appendSingle(" flowinsid in ({0}) and state={1} ", StringUtils.join(flowInsIds, ","), TapSystemConst.TapApprovalNodeStateEnum.Approveing);
            cboApprovalNodeInsService.updateByWhere(backUpdateMap, sql.toString());
        }
    }

    /**
     * @description: 校验任务是否可以退回
     * @param taskInfo
     * @param nodeEntity
     * @return java.util.Map<java.lang.String,java.lang.Object>
     * @author: wangxinhua
     * @date: 2023/6/20 15:43
     * @modify:
     */
    private Map<String, Object> validateBack(Map<String, Object> taskInfo, CboApprovalNodeEntity nodeEntity) {
        Map<String, Object> res = new HashMap<>();
        res.put("canBack", true);
        //如果人工增加任务
        if (ConvertUtil.convertToInt(taskInfo.get(CbbPmTaskEntity.FieldSource)) == PmSystemConst.TaskSource.ARTIFICIAL && !StringUtil.isEmpty(ConvertUtil.convertToString(taskInfo.get(CbbPmTaskEntity.FieldParentcode)))) {
            res.put("canBack", false);
            res.put("message", "当前任务为人工添加的子级任务，无法退回！");
            return res;
        }
        // 当前节点是否是审批节点
        if (!StringUtil.isEmpty(nodeEntity.getApprovalparam())) {
            JSONObject jsonObject = JSON.parseObject(nodeEntity.getApprovalparam());
            //如果是办理节点
            if ("0".equals(ConvertUtil.convertToString(jsonObject.get("isapporval")))) {
                res.put("canBack", false);
                res.put("message", "当前审批节点为办理节点，无法退回！");
                return res;
            }
        }
        return res;
    }

    /**
     * @description: 退回生成新一轮任务
     * @param docInfo
     * @param nodeEntity
     * @param nodeInsEntity
     * @return void
     * @author: wangxinhua
     * @date: 2023/6/20 15:43
     * @modify:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void backGenerateTaskInfo(Map<String, Object> docInfo, CboApprovalNodeEntity nodeEntity, CboApprovalNodeInsEntity nodeInsEntity, int useTimes) {
        //退回节点id
        String backNodeId = nodeEntity.getBackexp().substring(7);
        //查询退回的待办nodeins
        CboApprovalNodeEntity backNode = cboApprovalNodeService.queryById(backNodeId);
        CboApprovalNodeInsEntity backNodeIns = cboApprovalNodeInsService.queryObjectByWhere(" flowinsid="+nodeInsEntity.getFlowinsid() + " and state=1 and nodeid=" +backNodeId);
        //查询项目当前所有当前轮次任务
        StringBufferProxy nodeNotCompleteSql = new StringBufferProxy();
        nodeNotCompleteSql.appendSingle(" {0}='{1}' ", CbbPmTaskEntity.FieldProjectuucode, docInfo.get("projectuucode"));
        nodeNotCompleteSql.appendSingle(" and {0}='{1}' ", CbbPmTaskEntity.FieldCurrently, PmSystemConst.CboYesNo.YES);
        List<CbbPmTaskEntity> oldCurrentTaskEntity = cbbPmTaskService.queryByWhere(nodeNotCompleteSql.toString());
        List<Long> oldTaskId = oldCurrentTaskEntity.stream().map(item -> item.getId()).collect(Collectors.toList());
        //调用接口生成大而全的新一轮任务,其中轮数会+1，currently会赋值1
        Map<String, Object> operateWbsMap = new HashMap<>();
        operateWbsMap.put("operateType", PmSystemConst.OperateWbsType.BACKNODE);
        operateWbsMap.put("startNodeId", backNodeId);
        operateWbsMap.put("endNodeId", nodeEntity.getId());
        operateWbsMap.put("uuCode", docInfo.get("projectuucode"));
        operateWbsMap.put("flowInsId", nodeInsEntity.getFlowinsid());
        operateWbsMap.put("flowId", nodeInsEntity.getFlowid());
        operateWbsMap.put("sourceId", nodeInsEntity.getSourceid());
        operateWbsMap.put("sourceType", nodeInsEntity.getSourcetype());
        operateWbsMap.put("includeStart", true); //包含当前节点的任务生成
        operateWbsMap.put("useTimes", useTimes);
        wbsService.operateWbs(operateWbsMap);
        //获取新一轮次的所有任务
        StringBufferProxy newRoundSql = new StringBufferProxy();
        newRoundSql.appendSingle(" {0}='{1}' ", CbbPmTaskEntity.FieldProjectuucode, docInfo.get("projectuucode"));
        newRoundSql.appendSingle(" and {0}='{1}' ", CbbPmTaskEntity.FieldCurrently, PmSystemConst.CboYesNo.YES);
        List<CbbPmTaskEntity> cbbPmTaskEntityList = cbbPmTaskService.queryByWhere(newRoundSql.toString());
        //获取生成任务的审批节点id
        //获取节点信息
        List<String> nodeIds = new ArrayList<>();
        for (CbbPmTaskEntity cbbPmTaskEntity : cbbPmTaskEntityList) {
            if (!oldTaskId.contains(cbbPmTaskEntity.getId()) && !nodeIds.contains(cbbPmTaskEntity.getNodeid())) {
                nodeIds.add(cbbPmTaskEntity.getNodeid());
            }
        }
        //取消这些节点下所有任务
        nodeNotCompleteSql.clear();
        List<Map<String, Object>> updateTaskEntityList = new ArrayList<>();
        for (CbbPmTaskEntity cbbPmTaskEntity : oldCurrentTaskEntity) {
            System.out.println(cbbPmTaskEntity.getName());
            System.out.println(cbbPmTaskEntity.getFlowinsid());
            System.out.println(nodeInsEntity.getFlowinsid());
            //如果实在改动的节点内,未完成的任务
            if (nodeIds.contains(cbbPmTaskEntity.getNodeid()) && notCompleteStatus.contains(cbbPmTaskEntity.getStatus()) && ConvertUtil.convertToString(cbbPmTaskEntity.getFlowinsid()).equals(ConvertUtil.convertToString(nodeInsEntity.getFlowinsid()))) {
                Map<String, Object> updateItemMap = new HashMap<>();
                updateItemMap.put("id", cbbPmTaskEntity.getId());
                String remark = "由" + TaskStatusEnum.getNameByNumber(cbbPmTaskEntity.getStatus()) + "变更为" + TaskStatusEnum.BACK.getName();
                updateItemMap.put("description", remark);
                updateItemMap.put("status", TaskStatusEnum.BACK.getNumber());
                updateTaskEntityList.add(updateItemMap);
            }
        }
        cbbPmTaskService.updateBatchMap(updateTaskEntityList);
        //更新新增加任务信息
        updateTaskEntityList.clear();
        List<BasicEntity> updateNewTaskEntityList = new ArrayList<>();
        for (CbbPmTaskEntity insertTaskEntity : cbbPmTaskEntityList) {
            if (nodeIds.contains(insertTaskEntity.getNodeid()) && notCompleteStatus.contains(insertTaskEntity.getStatus()) && ConvertUtil.convertToString(insertTaskEntity.getFlowinsid()).equals(ConvertUtil.convertToString(nodeInsEntity.getFlowinsid()))) {
                String remark = "由于"+nodeEntity.getName()+"节点任务审批退回生成";
                insertTaskEntity.setDescription(remark);
                //如果任务节点为退回节点且任务状态为未开始
                if (backNodeId.equals(insertTaskEntity.getNodeid())) {
                    insertTaskEntity.setStatus(TaskStatusEnum.READYSTART.getNumber());
                    insertTaskEntity.setNodeinsid(ConvertUtil.convertToString(backNodeIns.getId()));
                    this.setPlanDate(insertTaskEntity, backNode, backNodeIns.getStartdate());
                }
                updateNewTaskEntityList.add(insertTaskEntity);
            }
        }
        cbbPmTaskService.updateBatch(updateNewTaskEntityList);
    }

    /**
     * @description: 人工任务退回
     * @param paramMap
     * @return void
     * @author: wangxinhua
     * @date: 2023/6/25 10:08
     * @modify:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void backLabourTask(Map<String, Object> paramMap) {
        if (StringUtil.isEmpty(ConvertUtil.convertToString(paramMap.get("taskid")))) {
            throw new MessageException("请选择任务");
        }
        CbbPmTaskEntity taskInfo = cbbPmTaskService.queryObjectByWhere("id=" + ConvertUtil.convertToString(paramMap.get("taskid")));
        if (!"0".equals(taskInfo.getParentcode())) {
            throw new MessageException("非一级人工任务无法退回");
        }
        int exists = cbbPmTaskBackRecordService.getCount(" code='"+taskInfo.getCode()+"' and handlestate="+TapSystemConst.TapApprovalFlowStateEnum.Approveing);
        if (exists > 0) {
            throw new MessageException("已存在正在审批的退回记录，请勿重复提交");
        }

        CbbPmTaskBackRecordEntity backRecordEntity = new CbbPmTaskBackRecordEntity();
        backRecordEntity.setProjectuucode(taskInfo.getProjectuucode());
        backRecordEntity.setWbscode(taskInfo.getWbscode());
        backRecordEntity.setCode(taskInfo.getCode());
        backRecordEntity.setName(taskInfo.getName());
        backRecordEntity.setIntroduction(taskInfo.getIntroduction());
        backRecordEntity.setPlanbegintime(taskInfo.getPlanbegintime());
        backRecordEntity.setPlanendtime(taskInfo.getPlanendtime());
        backRecordEntity.setPlanendtime(taskInfo.getPlanendtime());
        backRecordEntity.setPlanhours(taskInfo.getPlanhours());
        backRecordEntity.setResponsibleusercode(taskInfo.getResponsibleusercode());
        backRecordEntity.setResponsibleusername(taskInfo.getResponsibleusername());
        backRecordEntity.setBackopinion(ConvertUtil.convertToString(paramMap.get("backopinion")));
        backRecordEntity.setHandlestate(TapSystemConst.TapApprovalFlowStateEnum.Approveing);
        cbbPmTaskBackRecordService.insert(backRecordEntity);

        CboUserEntity cboUserEntity = cboUserService.queryById(ConvertUtil.convertToString(taskInfo.getCreateuser()));
        taskInfo.setResponsibleusername(cboUserEntity.getName());
        taskInfo.setResponsibleusercode(cboUserEntity.getCode());
        taskInfo.setDescription("人工增加任务退回");
        cbbPmTaskService.updateEntity(taskInfo);
    }

    /**
     * @description: 确认退回类型
     * @param paramMap
     * @return void
     * @author: wangxinhua
     * @date: 2023/6/25 10:23
     * @modify:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmBackLabourTask(Map<String, Object> paramMap) {
        if (StringUtil.isEmpty(ConvertUtil.convertToString(paramMap.get("taskcode")))) {
            throw new MessageException("请选择任务");
        }
        CbbPmTaskBackRecordEntity recordEntity = cbbPmTaskBackRecordService.queryObjectByWhere(" code='"+ConvertUtil.convertToString(paramMap.get("taskcode"))+"' and handlestate="+TapSystemConst.TapApprovalFlowStateEnum.Approveing);
        if (recordEntity == null) {
            throw new MessageException("未查询到未处理的退回记录");
        }
        recordEntity.setHandlestate(TapSystemConst.TapApprovalFlowStateEnum.Approved);
        recordEntity.setHandletype(ConvertUtil.convertToInt(paramMap.get("handletype")));

        Map<String, Object> confirmMap = new HashMap<>();
        CbbPmTaskEntity taskInfo = cbbPmTaskService.queryObjectByWhere(" code='"+ConvertUtil.convertToString(paramMap.get("taskcode"))+"' and currently="+ PmSystemConst.CboYesNo.YES);
        if (PmSystemConst.TaskBackType.TURN == ConvertUtil.convertToInt(paramMap.get("handletype"))) {
            //如果是转办,更新转办人
            confirmMap.put(CbbPmTaskEntity.FieldResponsibleusercode,ConvertUtil.convertToString(paramMap.get("turnusercode")));
            confirmMap.put(CbbPmTaskEntity.FieldResponsibleusername,ConvertUtil.convertToString(paramMap.get("turnusername")));
            confirmMap.put(CbbPmTaskEntity.FieldId,taskInfo.getId());
            confirmMap.put(CbbPmTaskEntity.FieldDescription,"转办");
            cbbPmTaskService.update(confirmMap);
            //保存转办人
            recordEntity.setTurnusercode(ConvertUtil.convertToString(paramMap.get("turnusercode")));
            recordEntity.setTurnusername(ConvertUtil.convertToString(paramMap.get("turnusername")));
        } else if (PmSystemConst.TaskBackType.BACK == ConvertUtil.convertToInt(paramMap.get("handletype"))) {
            //如果是退回则调用退回方法
            confirmMap.put("taskid", taskInfo.getId());
            this.backTask(confirmMap);
        } else if (PmSystemConst.TaskBackType.CLOSE == ConvertUtil.convertToInt(paramMap.get("handletype"))) {
            //如果是关闭则取消任务
//            confirmMap.put(CbbPmTaskEntity.FieldId, taskInfo.getId());
//            confirmMap.put(CbbPmTaskEntity.FieldStatus, TaskStatusEnum.CANCEL.getNumber());
//            cbbPmTaskService.update(confirmMap);
            Map<String, Object> closeMap = new HashMap<>();
            closeMap.put("projectuucode", taskInfo.getProjectuucode());
            closeMap.put("nodeids", taskInfo.getNodeid());
            closeMap.put("currently", PmSystemConst.CboYesNo.YES);
            closeMap.put("source", PmSystemConst.TaskSource.ARTIFICIAL);
            List<Map<String, Object>> closeList = this.getAllSubTaskByNode(closeMap, false);
            for (Map<String, Object> closeItem : closeList) {
                closeItem.put(CbbPmTaskEntity.FieldStatus, TaskStatusEnum.CANCEL.getNumber());
            }
            cbbPmTaskService.updateBatchMap(closeList);
            //查询节点下所有任务是否已完成，若都已完成则调用审批节点审批通过方法
            this.taskExecuteNextNode(taskInfo.convertToMap());
        }
        cbbPmTaskBackRecordService.updateEntity(recordEntity);
    }
    /**
     * @description: 项目编辑关闭任务
     * @param paramMap
     * @return void
     * @author: wangxinhua
     * @date: 2023/6/25 10:23
     * @modify:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void closeEditLabourTask(Map<String, Object> paramMap) {
        if (StringUtil.isEmpty(ConvertUtil.convertToString(paramMap.get("taskid")))) {
            throw new MessageException("请选择任务");
        }

        CbbPmTaskEntity taskInfo = cbbPmTaskService.queryObjectByWhere(" id="+ConvertUtil.convertToString(paramMap.get("taskid")));
        Map<String, Object> closeMap = new HashMap<>();
        closeMap.put("projectuucode", taskInfo.getProjectuucode());
        closeMap.put("nodeids", taskInfo.getNodeid());
        closeMap.put("currently", PmSystemConst.CboYesNo.YES);
        closeMap.put("source", PmSystemConst.TaskSource.ARTIFICIAL);
        List<Map<String, Object>> closeList = this.getAllSubTaskByNode(closeMap, false);
        for (Map<String, Object> closeItem : closeList) {
            if (ConvertUtil.convertToInt(closeItem.get(CbbPmTaskEntity.FieldStatus)) != TaskStatusEnum.COMPLETE.getNumber()) {
                closeItem.put(CbbPmTaskEntity.FieldStatus, TaskStatusEnum.CANCEL.getNumber());
            }
        }
        cbbPmTaskService.updateBatchMap(closeList);
        //查询节点下所有任务是否已完成，若都已完成则调用审批节点审批通过方法
        this.taskExecuteNextNode(taskInfo.convertToMap());
    }

    /**
     * @description: 生成sessionuserbean
     * @param userCode
     * @return com.topscomm.tap.common.SessionUserBean
     * @author: wangxinhua
     * @date: 2023/6/25 16:33
     * @modify:
     */
    public SessionUserBean generateSessionUserBean(String userCode, long userId) {
        StringBufferProxy sql = new StringBufferProxy();
        if (StringUtil.isEmpty(userCode)) {
            sql.appendSingle(" id={0} ", userId);
        } else {
            sql.appendSingle(" code='{0}' ", userCode);
        }
        CboUserEntity user = cboUserService.queryObjectByWhere(sql.toString());
        if (user == null) {
            throw new BusinessException("用户不存在！");
        }
        // 查询角色
        List<CboRoleEntity> roles = cboRoleService.queryRolesByUserId(user.getId());
        // 人事部门
        CboDeptEntity dept = cboDeptService.queryById("" + user.getDeptid());
        if (dept == null) {
            throw new BusinessException("没有查询到部门");
        }
        // 工作部门
        CboDeptEntity workDept = cboDeptService.queryById("" + user.getWorkdeptid());
        // 查询本部门和上级部门
        String deptids_user = "";
        List<String> filedList = new ArrayList<String>();
        filedList.add("code");
        filedList.add("orgid");
        filedList.add("id");
        List<Map<String, Object>> deptList = cboDeptService.queryMapFieldsByWhere("enabled=1", filedList);
        for (Map<String, Object> deptMap : deptList) {
            if (ConvertUtil.convertToString(deptMap.get("code")).length() > 0
                    && ConvertUtil.convertToString(dept.getCode())
                    .startsWith(ConvertUtil.convertToString(deptMap.get("code")))
                    && dept.getOrgid() == ConvertUtil.convertToLong(deptMap.get("orgid")))
                deptids_user += "," + ConvertUtil.convertToLong(deptMap.get("id"));
        }
        if (deptids_user.startsWith(",")) {
            deptids_user = deptids_user.substring(1);
        }
        // 人事组织
        CboOrgEntity org = cboOrgService.queryById("" + dept.getOrgid());
        // 工作组织
        CboOrgEntity workOrg = null;
        if (workDept != null) {
            workOrg = cboOrgService.queryById("" + workDept.getOrgid());
        }

        SessionUserBean sessionUserBean = new SessionUserBean();
        sessionUserBean.setUser(user);
        sessionUserBean.setOrg(org);
        sessionUserBean.setWorkOrg(workOrg);
        sessionUserBean.setDept(dept);
        sessionUserBean.setWorkDept(workDept);
        sessionUserBean.setRoleList(roles);
        return sessionUserBean;
    }

    /**
     * @description: 流程变更引起wbs变更
     * @return void
     * @author: hudeyong
     * @date: 2023/6/26
     * @modify:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeTaskByFlow(String uuCode, List<FlowNode> nodeList, Map<String, Object> pmWbsInfo, String parentCode,String flowInsId) {
        CbbPmWbsEntity pmWbsEntity = new CbbPmWbsEntity();
        pmWbsEntity.convertFromMap(pmWbsInfo);
        String nodeIds = nodeList.stream().map(item ->"'" + item.getId() + "'").collect(Collectors.joining(","));
        //以前生成的任务
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle("projectuucode = '{0}' and source = '{1}'",uuCode, PmSystemConst.TaskSource.FLOW);
        sql.appendSingle(" and nodeid in ({0})",nodeIds);
        sql.appendSingle(" and flowinsid = '{0}' and  CURRENTLY  = '{1}'",flowInsId, PmSystemConst.CboYesNo.YES);
        List<CbbPmTaskEntity> pmTaskEntities = cbbPmTaskService.queryByWhere(sql.toString());
        //先找到新增的任务,即nodeid在nodeList不在pmTaskEntities中的
        List<FlowNode> newNodeList = new ArrayList<>();
        Set<String> nodeIdSet = new HashSet<>();
        // 将pmTaskEntities中所有Map的id值添加到Set中
        for (CbbPmTaskEntity task : pmTaskEntities) {
            String nodeId = task.getNodeid();
            nodeIdSet.add(nodeId);
        }
        // 遍历nodeList，找到在nodeList中存在但在pmTaskEntities中不存在的Map对象
        for (FlowNode node : nodeList) {
            String nodeId = node.getId();
            if (!nodeIdSet.contains(nodeId)) {
                newNodeList.add(node);
            }
        }
        //先处理旧节点
        List<FlowNode> changeList = new ArrayList<>(nodeList);
        changeList.removeAll(newNodeList);
//        int looptimes = nodeList
        for(FlowNode node : changeList){
            String nodeid = node.getId();
            List<CbbPmTaskEntity> changeTaskList = pmTaskEntities.stream().filter(item -> item.getNodeid().equals(nodeid)).collect(Collectors.toList());
            changeTask(changeTaskList,node,pmWbsEntity,parentCode,flowInsId);
        }
        //再处理新增的节点，新节点直接新增即可
        List<BasicEntity> insertList = new ArrayList<>();
        for(FlowNode nodeInfo : newNodeList) {
            insertList.addAll(createTaskByNode(new HashMap<>(), nodeInfo,pmWbsEntity,parentCode,flowInsId,false,0,0));
        }
        cbbPmTaskService.insertBatch(insertList);
//        //最后处理被删除的,被删除的直接关闭即可
//        sql.clear();
//        // 没完成的、流程生成的、不在新列表里的，如果不是无效或被裁减都要设为无效
//        sql.appendSingle("projectuucode = '{0}' and source = '{1}' and  status != '{2}' and status > 0 and nodeid not in ({3})",
//                uuCode, PmSystemConst.TaskSource.FLOW,PmSystemConst.TaskStatus.COMPLETE,nodeIds);
//        List<CbbPmTaskEntity> delPmTaskEntities = cbbPmTaskService.queryByWhere(sql.toString());
//        loseTask(delPmTaskEntities, true);
//        List<FlowNode> newNode = nodeList.stream().filter()
        //flowId、sourceType

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeTaskByNode(Map<String, Object> wbsInfo,FlowNode node,Map<String,Object> paraMap) {
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle("PROJECTUUCODE = '{0}' AND NODEID = '{1}'",
                ConvertUtil.convertToString(wbsInfo.get("projectuucode")),ConvertUtil.convertToString(paraMap.get("nodeId")));
        //需要变更的节点任务
        List<CbbPmTaskEntity> pmTaskEntities = cbbPmTaskService.queryByWhere(sql.toString());
        CbbPmWbsEntity pmWbsEntity = new CbbPmWbsEntity();
        pmWbsEntity.convertFromMap(wbsInfo);
        String parentCode = findSingleNodeParentCode(pmTaskEntities);
        changeTask(pmTaskEntities,node,pmWbsEntity,parentCode,ConvertUtil.convertToString(paraMap.get("flowInsId")));
    }

    @Transactional(rollbackFor = Exception.class)
    public void changeTask(List<CbbPmTaskEntity> changeTaskList, FlowNode nodeInfo, CbbPmWbsEntity pmWbsEntity,String parentCode, String flowInsId) {
        boolean isSonFlow = PmSystemConst.NodeType.SONFLOW.equals(nodeInfo.getNodetype());
        //如果有效变无效，全部关闭
        int newRuningState = nodeInfo.getRuningState();
        List<CbbPmTaskEntity> runingTask = changeTaskList.stream().filter(item -> item.getStatus() >= 0).collect(Collectors.toList());
        if(runingTask.size() > 0 && newRuningState <= 0) {
            loseTask(changeTaskList, isSonFlow);
            return;
        }
        // 节点此时生成的任务
        List<BasicEntity> newTaskList =
                createTaskByNode(new HashMap<>(), nodeInfo,pmWbsEntity,parentCode, flowInsId,false,changeTaskList.get(0).getLooptimes(),changeTaskList.get(0).getUsetimes());
        //节点此时的审批人
        List<Map<String, Object>> userList = nodeInfo.getPlanUser();
        // 如果此时的目前还获取不到待审批人
        if(userList == null || userList.size() ==0) {
            // 如果新的节点没有生成待审批人，说明这个节点一定是未开始的，比较一下变化情况
            String responsibleusercode = changeTaskList.stream().map(item ->ConvertUtil.convertToString(item.getResponsibleusercode())).collect(Collectors.joining(","));
            if ("".equals(responsibleusercode)) {
                // 如果以前生成的任务们只有一个且责任人为空，说明没有变化，更新下任务状态就行，只会有一个待确定
                changeTaskList.get(0).setStatus(ConvertUtil.convertToInt(newTaskList.get(0).getValue(CbbPmTaskEntity.FieldStatus)));
                cbbPmTaskService.updateEntity(changeTaskList.get(0));
                return;
            } else {
                // 如果以前生成的任务们有多个或责任人不为空，说明现在的比以前少了，需要把以前的删除,重新生成
                Map<String, Object> timeMap = findMinMaxTime(changeTaskList);
                Date minStartTime = timeMap.containsKey("startTime") ? ConvertUtil.convertToDate(timeMap.get("startTime")):null;
                Date maxEndTime = timeMap.containsKey("endTime") ? ConvertUtil.convertToDate(timeMap.get("endTime")):null;
//                List<BasicEntity> newTaskList = createTaskByNode(nodeInfo,pmWbsEntity,parentCode, flowInsId,false,0,0);
                for(BasicEntity basicEntity : newTaskList) {
                    basicEntity.setValue(CbbPmTaskEntity.FieldPlanbegintime,minStartTime);
                    basicEntity.setValue(CbbPmTaskEntity.FieldPlanendtime,maxEndTime);
                }
                cbbPmTaskService.insertBatch(newTaskList);
                loseTask(changeTaskList, isSonFlow);
                //修改对应人工任务的parentcode
                changeArtificialTask(pmWbsEntity.getProjectuucode(),parentCode,nodeInfo);
                return;
            }
        }
        // 如果只有一条任务，且该任务没有审批人，且是单人节点，且现在有审批人了，
        if(PmSystemConst.NodeType.SINGLE.equals(nodeInfo.getNodetype())
                && changeTaskList.size()==1
                && ConvertUtil.convertToString(changeTaskList.get(0).getResponsibleusercode()).isEmpty()
                && userList.size()>0){
            changeTaskList.get(0).setResponsibleusercode(userList.get(0).get("code").toString());
            changeTaskList.get(0).setResponsibleusername(userList.get(0).get("name").toString());
            cbbPmTaskService.updateEntity(changeTaskList.get(0));
            return;
        }
        // 需要刷新的
        List<BasicEntity> updateList = new ArrayList<>();
        // 需要失效的
        List<CbbPmTaskEntity> loseList = new ArrayList<>();
        // 如果以前没有空任务，现在有空任务
        if(changeTaskList.size() == 1 && newTaskList.size() > 1 &&  !ConvertUtil.convertToString(changeTaskList.get(0).getResponsibleusercode()).isEmpty()){
            if (PmSystemConst.NodeType.COMPETITION.equals(nodeInfo.getNodetype())) {
                changeTaskList.get(0).setAutocomplete(PmSystemConst.CboYesNo.YES);
                changeTaskList.get(0).setResponsibleusercode("");
                changeTaskList.get(0).setResponsibleusername("");
                updateList.add(changeTaskList.get(0));
                changeTaskList.get(0).setRelation(PmSystemConst.TaskRelation.COMPETITION);
            } else if (PmSystemConst.NodeType.COUNTERSIGN.equals(nodeInfo.getNodetype()) || PmSystemConst.NodeType.COUNTERSIGNWAITING.equals(nodeInfo.getNodetype())) {
                changeTaskList.get(0).setRelation(PmSystemConst.TaskRelation.COUNTERSIGN);
                changeTaskList.get(0).setAutocomplete(PmSystemConst.CboYesNo.YES);
                changeTaskList.get(0).setResponsibleusercode("");
                changeTaskList.get(0).setResponsibleusername("");
                updateList.add(changeTaskList.get(0));
            } else if (PmSystemConst.NodeType.SONFLOW.equals(nodeInfo.getNodetype())) {
                // 子流程节点，生成一个任务且自动通过
                changeTaskList.get(0).setResponsibleusercode("");
                changeTaskList.get(0).setResponsibleusername("");
                changeTaskList.get(0).setAutocomplete(PmSystemConst.CboYesNo.YES);
                updateList.add(changeTaskList.get(0));
            }
        }
        // 如果有待审批人
        String nodeParentCode = findSingleNodeParentCode(changeTaskList);
        // 遍历旧任务，看旧任务责任人有没有在新生成的node审批人列表里
        for(CbbPmTaskEntity pmTaskEntity : changeTaskList) {
            String responsibleuserCode = ConvertUtil.convertToString(pmTaskEntity.getResponsibleusercode());
            int status = pmTaskEntity.getStatus();
            // 如果当前任务已经被完成或被裁剪，忽略
            if(PmSystemConst.TaskStatus.COMPLETE == status || PmSystemConst.TaskStatus.CUT == status){
                continue;
            }
            // 以前生成的审批人有没有在新生成的里面
            List<BasicEntity> tempList = newTaskList.stream().filter(item -> responsibleuserCode.equals(ConvertUtil.convertToString(item.getValue(CbbPmTaskEntity.FieldResponsibleusercode)))).collect(Collectors.toList());
            if (tempList.size()>0) {
                // 如果在，即以前生成的和现在生成的都有这个人
                if (PmSystemConst.TaskRuningState.CONFUSION == nodeInfo.getRuningState()) {
                    // 如果是待确定，设为待确定
                    pmTaskEntity.setStatus(PmSystemConst.TaskStatus.CONFUSION);
                } else if (PmSystemConst.TaskRuningState.LOSE == nodeInfo.getRuningState()) {
                    // 如果是失效，设为失效
                    pmTaskEntity.setStatus(PmSystemConst.TaskStatus.LOSE);
                } else if (PmSystemConst.TaskRuningState.VALID == nodeInfo.getRuningState()
                        && PmSystemConst.TaskStatus.READYSTART != status && PmSystemConst.TaskStatus.RUNNING != status) {
                    // 如果是有效,且不是待进行、进行中的，设为未开始
                    pmTaskEntity.setStatus(PmSystemConst.TaskStatus.NOTSTART);
                }
                updateList.add(pmTaskEntity);
            } else {
                // 如果不在，以前生成的有这个人，现在生成没有了
                pmTaskEntity.setStatus(PmSystemConst.TaskStatus.CANCEL);
                loseList.add(pmTaskEntity);
            }
        }
        loseTask(loseList, isSonFlow);
        cbbPmTaskService.updateBatch(updateList);
        // 查找新node中的审批人有没有在旧任务的责任人里
        for(BasicEntity basicEntity : newTaskList) {
            String usercode = ConvertUtil.convertToString(basicEntity.getValue(CbbPmTaskEntity.FieldResponsibleusercode));
            String username = ConvertUtil.convertToString(basicEntity.getValue(CbbPmTaskEntity.FieldResponsibleusername));
            List<CbbPmTaskEntity> tempUserList = changeTaskList.stream().filter(item -> ConvertUtil.convertToString(item.getResponsibleusercode()).equals(usercode)).collect(Collectors.toList());
            // 如果旧任务责任人里没有当前人员，说明当前人员是新增的，新增一下这个任务
            if (tempUserList.size() == 0) {
                Map<String, Object> timeMap = findMinMaxTime(changeTaskList);
                Date minStartTime = timeMap.containsKey("startTime") ? ConvertUtil.convertToDate(timeMap.get("startTime")):null;
                Date maxEndTime = timeMap.containsKey("endTime") ? ConvertUtil.convertToDate(timeMap.get("endTime")):null;
                CbbPmTaskEntity generalTask = new CbbPmTaskEntity();
                // 固定赋值：项目编号、wbs编号、来源流程、特殊任务、第一轮、任务效力跟随节点效力
                generalTask.setProjectuucode(pmWbsEntity.getProjectuucode());
                generalTask.setWbscode(pmWbsEntity.getWbscode());
                generalTask.setSource(PmSystemConst.TaskSource.FLOW);
                generalTask.setType(PmSystemConst.TaskType.SPECIAL);
                generalTask.setCurrently(1);
                generalTask.setFlowinsid(flowInsId);
                generalTask.setRound(1);
                generalTask.setFlowid(pmWbsEntity.getFlowid());
                generalTask.setEffectiveness(nodeInfo.getRuningState());
                // 肯定会有一个叫做node.name的任务，所以先赋值
                generalTask.setName(nodeInfo.getName());
                generalTask.setDeliverystatus(PmSystemConst.CboYesNo.YES);
                generalTask.setNodeid(nodeInfo.getId());
                generalTask.setSortCode(nodeInfo.getSortcode());
                // 默认任务效力为未开始
                int taskStatus = PmSystemConst.TaskStatus.NOTSTART;
                if (PmSystemConst.TaskRuningState.CONFUSION == nodeInfo.getRuningState()) {
                    // 如果是待确定
                    taskStatus = PmSystemConst.TaskStatus.CONFUSION;
                } else if (PmSystemConst.TaskRuningState.LOSE == nodeInfo.getRuningState()) {
                    taskStatus = PmSystemConst.TaskStatus.LOSE;
                }
                generalTask.setLooptimes(changeTaskList.get(0).getLooptimes());
                generalTask.setUsetimes(changeTaskList.get(0).getUsetimes());
                generalTask.setStatus(taskStatus);
                generalTask.setPlanbegintime(minStartTime);
                generalTask.setPlanendtime(maxEndTime);
                generalTask.setResponsibleusercode(usercode);
                generalTask.setResponsibleusername(username);
                long[] arrayId = PrimaryKeyUtil.GeneIDs(generalTask.getTableName(), 1);
                generalTask.setId(arrayId[0]);
                generalTask.setCode(PmSystemConst.CodePrefix.TASK+arrayId[0]);
                generalTask.setParentcode(nodeParentCode.isEmpty() ? parentCode : nodeParentCode);
                cbbPmTaskService.insert(generalTask);
            }
        }
    }

    //处理人工任务
    public void changeArtificialTask(String uuCode, String paerntCode, FlowNode nodeInfo){
        String nodeid = nodeInfo.getId();
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" UPDATE CBB_PM_TASK SET PARENTCODE = '{0}'",paerntCode);
        sql.appendSingle(" WHERE SOURCE = '1' and NODEID = '{0}' and PROJECTUUCODE = '{1}'",nodeid,uuCode);
        cbbPmTaskService.updateExecute(sql.toString());
    }

    public String findSingleNodeParentCode(List<CbbPmTaskEntity> taskList) {
        String parentCode = "";
        // 无人办理只有一条的，一定是待定的唯一主任务
        if (taskList.size() == 1 && ConvertUtil.convertToString(taskList.get(0).getResponsibleusercode()).isEmpty()) {
            parentCode = taskList.get(0).getCode();
        }
        Set<String> parentCodeSet = new HashSet<>();
        // 获取所有parentCode
        for (CbbPmTaskEntity task : taskList) {
            parentCodeSet.add(task.getParentcode());
        }
        // 去除code在 parentCodeSet 中的数据
        for (CbbPmTaskEntity task : taskList) {
            if(parentCodeSet.contains(task.getCode())) {
                parentCode = task.getCode();
                break;
            }
        }
        return parentCode;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void loseTask(List<FlowNode> nodeList, Boolean isSonFlow, String uuCode, String flowInsId) {
        // 排除掉无源头的
        nodeList = nodeList.stream().filter(item-> !item.getApprovalParam().containsKey("nosource")).collect(Collectors.toList());
        String nodeIds = nodeList.stream().map(item ->"'" + item.getId() + "'").collect(Collectors.joining(","));
        StringBufferProxy sql = new StringBufferProxy();
        sql.clear();
        // 没完成的、流程生成的、不在新列表里的，如果不是无效或被裁减都要设为无效
        sql.appendSingle("projectuucode = '{0}' and source = '{1}' and  status != '{2}' and status >= 0 and nodeid not in ({3}) and flowInsId = '{4}'",
                uuCode, PmSystemConst.TaskSource.FLOW,PmSystemConst.TaskStatus.COMPLETE,nodeIds,flowInsId);
        List<CbbPmTaskEntity> delPmTaskEntities = cbbPmTaskService.queryByWhere(sql.toString());
        loseTask(delPmTaskEntities, isSonFlow);
    }

    @Transactional(rollbackFor = Exception.class)
    public void loseTask(List<CbbPmTaskEntity> taskList, boolean isSonFlow) {
        if(taskList.size()==0){
            return;
        }
        Set<String> taskCodeSet = new HashSet<>();
        List<BasicEntity> updateList = new ArrayList<>();
        for(CbbPmTaskEntity pmTaskEntity : taskList) {
            if(pmTaskEntity.getStatus() < 0) {
                continue;
            }
            pmTaskEntity.setStatus(PmSystemConst.TaskStatus.CANCEL);
            pmTaskEntity.setCurrently(PmSystemConst.CboYesNo.NO);
            String code = pmTaskEntity.getCode();
            taskCodeSet.add(code);
            updateList.add(pmTaskEntity);
        }
        if (isSonFlow && taskCodeSet.size() > 0) {
            StringBuilder sb = new StringBuilder();
            for (String element : taskCodeSet) {
                if (sb.length() > 0) {
                    sb.append(", ");
                }
                sb.append("'").append(element).append("'");
            }
            StringBufferProxy sql = new StringBufferProxy();
            sql.appendSingle("SELECT * FROM CBB_PM_TASK START WITH code IN ({0}) AND STATUS > 0 CONNECT BY PRIOR code = parentcode",sb.toString());
            List<Map<String, Object>> sonTaskList = cbbPmTaskService.selectExecute(sql.toString());
            for(Map<String, Object> map : sonTaskList) {
                CbbPmTaskEntity pmTaskEntity = new CbbPmTaskEntity();
                pmTaskEntity.convertFromMap(map);
                pmTaskEntity.setStatus(PmSystemConst.TaskStatus.CANCEL);
                pmTaskEntity.setCurrently(PmSystemConst.CboYesNo.NO);
                updateList.add(pmTaskEntity);
            }
        }
        cbbPmTaskService.updateBatch(updateList);
    }
    public Map<String, Object> findMinMaxTime(List<CbbPmTaskEntity> taskList) {
        Date minStartTime = null;
        Date maxEndTime = null;
        for (CbbPmTaskEntity task : taskList) {
            Date startTime = task.getPlanbegintime();
            Date endTime = task.getPlanendtime();
            if (startTime != null) {
                if (minStartTime == null || startTime.before(minStartTime)) {
                    minStartTime = startTime;
                }
                if (maxEndTime == null || endTime.after(maxEndTime)) {
                    maxEndTime = endTime;
                }
            }
        }
        Map<String, Object> resultMap = new HashMap<>();
        if(minStartTime!=null){
            resultMap.put("startTime",minStartTime);
        }
        if(maxEndTime!=null){
            resultMap.put("endTime",maxEndTime);
        }
        return resultMap;
    }

    @Override
    public List<Map<String, Object>> getAllSubTaskByNode(Map<String,Object> paraMap, Boolean returnFlow) {
        String uuCode = ConvertUtil.convertToString(paraMap.get("projectuucode"));
        String nodeIds = ConvertUtil.convertToString(paraMap.get("nodeids"));
        StringBufferProxy sql = new StringBufferProxy();
        StringBufferProxy resSql = new StringBufferProxy();
        sql.appendSingle(" projectuucode='{0}' ",uuCode);
        resSql.appendSingle(" projectuucode='{0}' ",uuCode);
        sql.appendSingle(" and nodeid in ({0}) ",nodeIds);
        if (paraMap.containsKey("currently")) {
            sql.appendSingle(" and currently={0} ", paraMap.get("currently"));
            resSql.appendSingle(" and currently={0} ", paraMap.get("currently"));
        }
        if (paraMap.containsKey("source")) {
            sql.appendSingle(" and source={0} ", paraMap.get("source"));
            resSql.appendSingle(" and source={0} ", paraMap.get("source"));
        }
        if (paraMap.containsKey("flowinsid")) {
            sql.appendSingle(" and flowinsid={0} ", paraMap.get("flowinsid"));
        }
        Map<String, Object> queryMap = new HashMap<>();
        queryMap.put("whereSql", sql.toString());
        queryMap.put("whereResSql", resSql.toString());
        //获取项目下节点下所有任务
        if (returnFlow) {
            return cbbPmTaskService.queryMap(queryMap, "queryAllSubFlowinsidTaskByNode");
        }else {
            return cbbPmTaskService.queryMap(queryMap, "queryAllSubTaskByNode");
        }
    }
}
